package com.tutu.utils;

import com.tutu.controller.CommonsController;
import com.tutu.controller.backend.BackendIndexController;
import com.tutu.core.Constant;
import com.tutu.core.api.UserApiUrls;
import com.tutu.entity.vo.DataEntity;
import com.tutu.entity.vo.weixin.WxMsgVo;
import com.tutu.entity.vo.weixin.WxUser;
import com.tutu.service.impl.UserServiceImpl;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONArray;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
@Slf4j
public class WxMsgPushUtil {

    public static String wechat_oauth_Url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";

    public static final String appid = ConfigUtil.getString("wechat.appId");

    public static final String secret = ConfigUtil.getString("wechat.secret");

    public static final String personCenterUrl = ConfigUtil.getString("person.center.url");

    public static final String timeDataUrl = ConfigUtil.getString("time.data.url");

    public static final String historyMsgUrl = ConfigUtil.getString("history.msg.url");

    // 缓存 access_token 和 jsapi_ticket
    public static String accessToken = "";
    public static String jsapiTicket = "";
    public static long tokenExpireTime;  // token过期时间戳
    public static long ticketExpireTime; // ticket过期时间戳

    public static String getToken() {
        try {
            if (!BackendIndexController.refreshTokenStatus) return accessToken;

            // 检查缓存是否有效
            if (StringUtils.isNotBlank(accessToken) && System.currentTimeMillis() < tokenExpireTime) return accessToken;

            String getTokenApi = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret;

            String tokenJsonStr = WebUtil.doGetPost(getTokenApi, "GET", null);

            log.info("获取token:" + tokenJsonStr);

            Map<String, Object> map = JsonUtil.json2Map(tokenJsonStr);

            if (map.containsKey("access_token")) {
                accessToken = map.get("access_token") + "";

                // 提前5分钟过期，避免临界点问题
                int expiresIn = Integer.parseInt(map.get("expires_in") + "");
                tokenExpireTime = System.currentTimeMillis() + (expiresIn - 300) * 1000L;
            } else {
                Thread.sleep(3000L);

                accessToken = getToken();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return accessToken;
    }

    /**
     * 获取 jsapi_ticket（带缓存机制）
     */
    public static String getJsapiTicket() {
        // 检查缓存是否有效
        if (jsapiTicket != null && System.currentTimeMillis() < ticketExpireTime) return jsapiTicket;

        String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + getToken() + "&type=jsapi";

        try {
            String jsonStr = WebUtil.doGetPost(url, "GET", null);

            Map<String, Object> map = JsonUtil.json2Map(jsonStr);

            if (map.containsKey("ticket") && map.get("errcode").equals(0)) {
                jsapiTicket = map.get("ticket") + "";

                // 提前5分钟过期
                int expiresIn = Integer.parseInt(map.get("expires_in") + "");
                ticketExpireTime = System.currentTimeMillis() + (expiresIn - 300) * 1000L;
            } else {
                String errMsg = "获取jsapi_ticket失败: " + map.get("errmsg");
                throw new RuntimeException(errMsg);
            }
        } catch (Exception e) {
            throw new RuntimeException("获取jsapi_ticket异常: " + e.getMessage(), e);
        }

        return jsapiTicket;
    }

    /**
     * 生成JS-SDK签名
     *
     * @param url 当前页面的完整URL（不包含#及其后面部分）
     * @return 签名结果
     */
    public static Map<String, String> generateSignature(String url) {
        String jsapiTicket = getJsapiTicket();
        String nonceStr = generateNonceStr();
        long timestamp = System.currentTimeMillis() / 1000;

        // 1. 按照字段名ASCII字典序排序
        String string1 = "jsapi_ticket=" + jsapiTicket + "&noncestr=" + nonceStr + "&timestamp=" + timestamp + "&url=" + url;

        // 2. SHA1加密
        String signature = sha1(string1);

        Map<String, String> result = new HashMap<>();
        result.put("appId", appid);
        result.put("timestamp", String.valueOf(timestamp));
        result.put("nonceStr", nonceStr);
        result.put("signature", signature);
        result.put("url", url); // 用于调试

        return result;
    }

    /**
     * 生成随机字符串
     */
    private static String generateNonceStr() {
        return java.util.UUID.randomUUID().toString().replace("-", "").substring(0, 16);
    }

    /**
     * SHA1加密方法
     */
    private static String sha1(String input) {
        try {
            java.security.MessageDigest md = java.security.MessageDigest.getInstance("SHA-1");
            byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8));
            StringBuilder hexString = new StringBuilder();
            for (byte b : digest) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) hexString.append('0');
                hexString.append(hex);
            }
            return hexString.toString();
        } catch (Exception e) {
            throw new RuntimeException("SHA1加密失败", e);
        }
    }

    public static String getUnionIdByOpenId(String openId) {
        String getUnionIdApi = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + getToken() + "&openid=" + openId + "&lang=zh_CN";
        String unionIdJsonStr = WebUtil.doGetPost(getUnionIdApi, "GET", null);
        log.info("通过微信用户OpenId获取UnionId返回结果：" + unionIdJsonStr);
        Map<String, Object> map = JsonUtil.json2Map(unionIdJsonStr);

        if (map.containsKey("unionid")) return map.get("unionid").toString();

        return "";
    }

    public static void clearQuota() {
        Map<String, Object> paramMap = new HashMap<>();
        String getUnionIdApi = "https://api.weixin.qq.com/cgi-bin/clear_quota?access_token=" + getToken();

        paramMap.put("appid", ConfigUtil.getString("wechat.appId"));

        log.info(WebUtil.doGetPost(getUnionIdApi, "POST", paramMap));
    }

    /**
     * 接收预警消息服务推送的消息
     *
     * @param content 文本内容
     */
    public static void receiveMsg(String type, String content, String name, Long recordTime, String openId) {
        // 拼接微信消息体
        WxMsgVo wxMsgVo = new WxMsgVo();

        wxMsgVo.setUserOpenId(openId);
        wxMsgVo.setTypeValue(type);  // 预警类别
        wxMsgVo.setNameValue(name);  // 预警范围
        wxMsgVo.setTimeValue(DateUtils.longToStringWithFormat(recordTime, Constant.TIME_FORMAT_DEFAULT));  // 发布时间
        wxMsgVo.setContentValue(content);  // 预警内容
        wxMsgVo.setUrl(getWeChatMenuUrl(historyMsgUrl));

        CommonsController.executorService.submit(() -> sendWeChatMsg(wxMsgVo, true));
    }

    public static void sendWeChatMsg(WxMsgVo wxMsgVo, boolean isNotice) {
        if (null == wxMsgVo) return;

        try {
            String sendMsgApi = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + getToken();
            String template_id;

            if (isNotice) {
                template_id = "nxaTZqcvPu2hVuIyTyvR1IVgZCDEP_DvxChqbJWTZig";
            } else {
                template_id = "ulUrkQCaFk0vdDqoyDZD_xGIBzso2btcOHgfZha23KI";
            }

            Map<String, Object> paramMap = new HashMap<>();
            Map<String, Object> dataMap = new HashMap<>();

            dataMap.put("keyword1", new DataEntity(wxMsgVo.getTypeValue(), wxMsgVo.getTypeColor()));
            dataMap.put("keyword2", new DataEntity(wxMsgVo.getNameValue(), wxMsgVo.getNameColor()));
            dataMap.put("keyword3", new DataEntity(wxMsgVo.getTimeValue(), wxMsgVo.getTimeColor()));
            dataMap.put("keyword4", new DataEntity(wxMsgVo.getContentValue(), wxMsgVo.getContentColor()));
            paramMap.put("touser", wxMsgVo.getUserOpenId());
            paramMap.put("url", wxMsgVo.getUrl());
            paramMap.put("template_id", template_id);
            paramMap.put("data", dataMap);

            if (BackendIndexController.refreshTokenStatus) {
                Map<String, Object> map = JsonUtil.json2Map(WebUtil.doGetPost(sendMsgApi, "POST", paramMap));

                log.info(DateUtils.getNowTime() + " 发送微信消息返回值：" + map);

                // 如果返回的内容提示该微信用户openId有误，则自动删除该用户相关的所有信息
                if (map.containsKey("errmsg") && map.get("errmsg").equals("invalid openid")) {
                    Map<String, Object> userMap = UserServiceImpl.getInfoByOpenId(wxMsgVo.getUserOpenId());

                    if (userMap.containsKey("id")) {
                        log.info("删除openId有误的微信用户信息及相关数据：{}", userMap);

                        HttpRequestUtil.getCompleteData(UserApiUrls.base_prefix + UserApiUrls.delete, "id=" + userMap.get("id"));
                    }
                }
            } else {
                log.info("预警类别：{}，预警内容：{}，预警范围：{}，发布时间：{}，接收用户：{}", wxMsgVo.getTypeValue(), wxMsgVo.getContentValue(), wxMsgVo.getNameValue(), wxMsgVo.getTimeValue(), wxMsgVo.getUserOpenId());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static List<String> getUserList() {
        List<String> list = new ArrayList<>();

        try {
            String getUserListApi = "https://api.weixin.qq.com/cgi-bin/user/get?access_token=" + getToken();
            String userListJsonStr = WebUtil.doGetPost(getUserListApi, "GET", null);
            for (Object openid : JSONArray.fromObject(JsonUtil.json2Map(JsonUtil.json2Map(userListJsonStr).get("data")).get("openid")))
                list.add(openid + "");
        } catch (Exception e) {
            e.printStackTrace();
        }

        return list;
    }

    public static WxUser getWxUserInfo(String code) {
        WxUser wxUser = new WxUser();

        if (StringUtils.isBlank(code)) return wxUser;

        Map<String, Object> map = getUserToken(code);

        if (map.containsKey("access_token")) {
            String access_token = map.get("access_token").toString();
            String openId = map.get("openid").toString();

            map = getUserInfo(access_token, openId);

            if (map.containsKey("nickname")) {
                wxUser.setOpenId(map.get("openid").toString());
                wxUser.setNickname(map.get("nickname").toString());
                wxUser.setSex(Integer.parseInt(map.get("sex").toString()));
                wxUser.setHeadImgUrl(map.get("headimgurl").toString());
            }
        }

        return wxUser;
    }

    public static Map<String, Object> getUserInfo(String accessToken, String openId) {
        String getUserListApi = "https://api.weixin.qq.com/sns/userinfo?access_token=" + accessToken + "&openid=" + openId + "&lang=zh_CN";
        String userListJsonStr = WebUtil.doGetPost(getUserListApi, "GET", null);
        log.info(userListJsonStr);
        return JsonUtil.json2Map(userListJsonStr);
    }

    public static Map<String, Object> getUserToken(String code) {
        String getUserListApi = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + appid + "&secret=" + secret + "&code=" + code + "&grant_type=authorization_code";
        String userListJsonStr = WebUtil.doGetPost(getUserListApi, "GET", null);
        log.info(userListJsonStr);
        return JsonUtil.json2Map(userListJsonStr);
    }

    public static Map<String, Object> refreshUserToken(String refreshToken) {
        String getUserListApi = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=" + appid + "&grant_type=refresh_token&refresh_token=" + refreshToken;
        String userListJsonStr = WebUtil.doGetPost(getUserListApi, "GET", null);
        log.info(userListJsonStr);
        return JsonUtil.json2Map(userListJsonStr);
    }

    public static Map<String, Object> getUserInfo(String openid) {
        String getUserListApi = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + getToken() + "&openid=" + openid + "&lang=LANG";
        String userListJsonStr = WebUtil.doGetPost(getUserListApi, "GET", null);
        log.info(userListJsonStr);
        return JsonUtil.json2Map(userListJsonStr);
    }

    public static String getWeChatMenuUrl(String url) {
        return WxMsgPushUtil.wechat_oauth_Url.replace("APPID", appid).replace("REDIRECT_URI", URLEncoder.encode(url));
    }
}